#include "WProgram.h"
#include "IRcommunication.h"

void IRcommunication::begin(uint8_t pinEmmiter, uint8_t pinReceiver){
  irLed = pinEmmiter;
  irReceiver = pinReceiver;
}

void IRcommunication::send(unsigned int message) {
  uint8_t parity = 0;
  uint8_t bit;
  noInterrupts();

  sendPulse(headerDuration);
  sendDelay();
  for (int i=0; i<16; i++) {
    bit = message>>i & 0x01;
    parity += bit;
    sendBit(bit);
    sendDelay();
  }
  sendBit(parity & 0x01);
  interrupts();
}

void IRcommunication::sendBit(bool bit) {
  if (bit) {
    sendPulse(oneDuration);
  }
  else {
    sendPulse(zeroDuration);
  }
}

void IRcommunication::sendPulse(unsigned int duration) {
  unsigned int elapsedTime = 0;
  while (elapsedTime < duration) {

    digitalWrite(IRcommunication::irLed,HIGH);
    asm("nop\n nop\n nop\n nop\n nop\n nop\n");
    asm("nop\n nop\n nop\n nop\n nop\n nop\n");
    asm("nop\n nop\n nop\n");  
    delayMicroseconds(halfPeriod);
    digitalWrite(IRcommunication::irLed,LOW);
    asm("nop\n nop\n nop\n nop\n nop\n nop\n");
    asm("nop\n nop\n nop\n nop\n nop\n nop\n");
    asm("nop\n nop\n nop\n");  
    delayMicroseconds(halfPeriod);

    elapsedTime += 26;
  }
}

/*wait time between bits*/
void IRcommunication::sendDelay() {
  delayMicroseconds(delayDuration); 
}


/*
 * main function for receiving, it should 
 * be called as an interruption whenever an IR beam
 * hits one of the sensors
 * TODO add brief description of the signal here
 * add long description of the signal at the wiki
 */
int IRcommunication::receive(){
  //we don't want the reception of one signal to be blocked by another
  noInterrupts();
  unsigned int duration = 0;
  while(!digitalRead(irReceiver)){
    duration += 5;
  }
  if (duration<2600 && duration > 2200) {
    unsigned int message = 0;
    uint8_t parity = 0;
    boolean keepReading = true;
    uint8_t i = 0;
    while(keepReading){
      duration = pulseIn(irReceiver,LOW);
      if (duration > 400 && duration < 1400) {
        if(duration > 900){
          if(i!=16){
            //will not read the info of the last number,  it's just the parity check
            message = message | B1<<i; //just readed a 1
          }
          parity += 1;
        }                     
        //any value that is greater than 400 but less than 900 is considered a 0
        //do not need to treat zeroes
      }
      else {
        //one of the values is less than 0 or more than 1
        disableFlagExtInt1();
        return 0; 
      }
      //end of one iteration, check to keep reading
      if(i==16){
        keepReading = false;
      }
      else {
        i++;
      }
    }
    //we should have the message stored at  message f we did 17 steps of the
    //i bucle (i == 16) we have an entire and maybe true message
    if(i!=16){
      //not enough bits
      disableFlagExtInt1();
      return 0;
    }
    else {
      if(!(parity & 0x01)){
        return message;
      }
      else {
        //parity error
        disableFlagExtInt1();
        return 0;
      }
    }
  }
  else {
    //missing header
    disableFlagExtInt1();
    return 0;
  }
  disableFlagExtInt1();
  return 0;
}



